package ffte.test

import breeze.math.Complex

import ffte.evaluate.cases.{Sim,FFTCase}
import ffte.algorithm.FFTGen.{ffter,Winograd}
import ffte.native.{Native,NIFFT,NFFT}
import ffte.algorithm.FFTGen
import ffte.evaluate.vectors.Cplx

/**
 * Native FFT test harness
 *
 * This object provides a comprehensive test harness for validating native
 * FFT implementations against expected results. It supports both single
 * tests and batch testing of multiple transform sizes.
 *
 * Test Capabilities:
 * - Single transform testing with detailed debug output
 * - Batch testing of multiple transform sizes
 * - Forward and inverse FFT validation
 * - Configurable error tolerance and debug levels
 * - Support for both deterministic and random FFT generation
 *
 * Usage Examples:
 * - Test single transform: NativeStudy.main(Array("0", "false", "64", "10"))
 * - Run batch tests: NativeStudy.main(Array("0", "false"))
 * - Test with random generation: NativeStudy.main(Array("1", "false"))
 */
object NativeStudy extends Sim {

    /** Convert test vector complex to Breeze complex */
    def ci2c(x:Cplx) = Complex(x.re,x.im)

    /**
     * Run simulation for native FFT validation
     *
     * Executes the FFT simulation using the provided FFT structure
     * and compares results against expected outputs from test vectors.
     *
     * @param fp Generated FFT structure
     * @param _inv Inverse FFT mode flag
     * @return Tuple of (overall pass/fail status, failure count)
     */
    def sim(fp:ffter[Native],_inv:Boolean) : (Boolean,Int) = {
        inv = _inv
        N = fp.rN
        val tv = test_vectors
        val fft = if(inv) new NIFFT(fp,S) else new NFFT(fp,S)
        done({
            failcnt = 0
        },{
            val frame = idx%CC
            val d : Array[Complex] = tv(frame).d.map(ci2c(_))
            val q : Array[Complex] = tv(frame).q.map(ci2c(_))
            val tq = fft.transform(d)
            for (i <- 0 until N) {
                val o = q(i)
                val r = tq(i)
                if((o-r).abs>32.0) {
                    ook = false
                    ok  = false
                    if(debug>0) {
                        println(s"$i: (out:$o right:$r)")
                    }
                }
                if(debug>2) {
                    println(s"$i: (out:$o right:$r)")
                }
            }
            if(!ook) failcnt += 1
            next
        })
        (failcnt!=C,failcnt)
    }

    /**
     * Run single test case
     *
     * Executes a single test for a specific transform size with
     * detailed debug output for analysis.
     *
     * @param n Transform size
     * @param k Test vector pattern
     * @param inv Inverse FFT mode flag
     */
    def singleTest(n:Int,k:Int,inv:Boolean):Unit = {
        debug = 3
        val s = FFTCase.shift(n)
        S = s
        K = k
        Winograd
        val fp = if(rgen) FFTGen.rgen[Native](n) else FFTGen.gen[Native](n)
        val (ook,failcnt) = sim(fp,inv)
        if(ook) println(s"$n($inv): PASS($failcnt)") else println(s"$n: FAIL")
    }

    /**
     * Run batch test cases
     *
     * Executes multiple test cases for different transform sizes
     * and configurations. Provides summary results.
     *
     * @param cases Map of transform sizes to scaling factors
     * @param inv Inverse FFT mode flag
     */
    def caseTest(cases:Map[Int,Int],inv:Boolean): Unit = {
        K = 0
        debug = 1
        cases.map { case (n,s) =>
            S = s
            Winograd
            val fp = if(rgen) FFTGen.rgen[Native](n) else FFTGen.gen[Native](n)
            val (ook,failcnt) = sim(fp,inv)
            if(ook) println(s"$n($inv): PASS($failcnt)") else println(s"$n: FAIL")
            (n,ook,failcnt)
        }.foreach{case (n,ook,failcnt) =>
            if(ook) println(s"$n($inv): PASS($failcnt)") else println(s"$n: FAIL")
        }
    }

    /**
     * Main entry point for native FFT testing
     *
     * Command line arguments:
     * args(0): Random generation flag (0=deterministic, 1=random)
     * args(1): Inverse FFT flag (0=forward, 1=inverse)
     * args(2): Transform size (for single test)
     * args(3): Test pattern (for single test)
     *
     * @param args Command line arguments
     */
    def main(args: Array[String]) {
        ffte.default.core.GlobeSetting.evaluateNative = true
        if(args.length>0) {
            if(args(0).toInt==1) rgen = true
        }
        val inv = if(args.length>1) (args(1).toInt==1) else false
        if(args.length>2) {
            val n = args(2).toInt
            val k = args(3).toInt
            singleTest(n,k,inv)
        } else caseTest(FFTCase.cases,inv)
    }
}